
#ifndef XDNS_PROTOCOL_H
#define XDNS_PROTOCOL_H

/*
    Header section format from RFC 1035,

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      ID                       |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    QDCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ANCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    NSCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                    ARCOUNT                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

   Question section format from RFC 1035,

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                     QNAME                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     QTYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     QCLASS                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

   Resource record format from RFC 1035,

                                    1  1  1  1  1  1
      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                                               |
    /                                               /
    /                      NAME                     /
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TYPE                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                     CLASS                     |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                      TTL                      |
    |                                               |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
    |                   RDLENGTH                    |
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
    /                     RDATA                     /
    /                                               /
    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*/

/*! The default size of one UDP packet. */
#define XDNS_UDP_PACKET_SIZE 512

/*! The total size of DNS header. */
#define XDNS_HEADER_SIZE 12

/*! The max size of one name label. */
#define XDNS_MAX_LABEL_SIZE 63


/* CLASS fields appear in resource records. */

/*! The Internet. */
const unsigned short XDNS_CLASS_IN = 1;


/* TYPE fields are used in resource records. */

/*! A host address. */
const unsigned short XDNS_TYPE_A = 1;

/*! A domain name pointer. */
const unsigned short XDNS_TYPE_PTR = 12;


/* Opcode assigned in the request header section. A four bit field that
   specifies kind of query in this message. This value is set by the
   originator of a query and copied into the response.
*/

/*! A standard query (QUERY). */
const unsigned char XDNS_OPCODE_QUERY = 0;


/* Response code (RCODE) assigned in the request header section. A four
   bit field is set as part of responses.
*/

/*! No error condition. */
const unsigned char XDNS_RCODE_NO_ERROR = 0;

/*! Format error.
    @see XE_RcodeFormatError.
*/
const unsigned char XDNS_RCODE_FORMAT_ERROR = 1;

/*! Server failure.
    @see XE_RcodeServerFailure.
*/
const unsigned char XDNS_RCODE_SERVER_FAILURE = 2;

/*! Name Error.
    @see XE_RcodeNameError.
*/
const unsigned char XDNS_RCODE_NAME_ERROR = 3;

/*! Not Implemented.
    @see XE_RcodeNotImplemented.
*/
const unsigned char XDNS_RCODE_NOT_IMPLEMENTED = 4;

/*! Refused.
    @see XE_RcodeRefused.
*/
const unsigned char XDNS_RCODE_REFUSED = 5;

// 6-15, Reserved for future use.


/*! The label is specfied as an indirection pointer if the first byte
    corresponds to this mask.
*/
const unsigned char XDNS_INDIRECTION_MASK = 0xc0;


unsigned short XDNS_GET_16BIT(unsigned char* buffer);
long XDNS_GET_32BIT(unsigned char* buffer);
void XDNS_SET_16BIT(unsigned char* buffer,
                    unsigned short value);
void XDNS_SET_32BIT(unsigned char* buffer,
                    long value);

// Start from the base pointer of the header section.
unsigned short XDNS_GET_HEADER_ID(unsigned char* header);
unsigned char XDNS_GET_HEADER_QR(unsigned char* header);
unsigned char XDNS_GET_HEADER_OPCODE(unsigned char* header);
unsigned char XDNS_GET_HEADER_AA(unsigned char* header);
unsigned char XDNS_GET_HEADER_TC(unsigned char* header);
unsigned char XDNS_GET_HEADER_RD(unsigned char* header);
unsigned char XDNS_GET_HEADER_RA(unsigned char* header);
unsigned char XDNS_GET_HEADER_Z(unsigned char* header);
unsigned char XDNS_GET_HEADER_RCODE(unsigned char* header);
unsigned short XDNS_GET_HEADER_QDCOUNT(unsigned char* header);
unsigned short XDNS_GET_HEADER_ANCOUNT(unsigned char* header);
unsigned short XDNS_GET_HEADER_NSCOUNT(unsigned char* header);
unsigned short XDNS_GET_HEADER_ARCOUNT(unsigned char* header);
void XDNS_SET_HEADER_ID(unsigned char* header,
                        unsigned short value);
void XDNS_SET_HEADER_QR(unsigned char* header,
                        unsigned char value);
void XDNS_SET_HEADER_OPCODE(unsigned char* header,
                            unsigned char value);
void XDNS_SET_HEADER_AA(unsigned char* header,
                        unsigned char value);
void XDNS_SET_HEADER_TC(unsigned char* header,
                        unsigned char value);
void XDNS_SET_HEADER_RD(unsigned char* header,
                        unsigned char value);
void XDNS_SET_HEADER_RA(unsigned char* header,
                        unsigned char value);
void XDNS_SET_HEADER_Z(unsigned char* header,
                       unsigned char value);
void XDNS_SET_HEADER_RCODE(unsigned char* header,
                           unsigned char value);
void XDNS_SET_HEADER_QDCOUNT(unsigned char* header,
                             unsigned short value);
void XDNS_SET_HEADER_ANCOUNT(unsigned char* header,
                             unsigned short value);
void XDNS_SET_HEADER_NSCOUNT(unsigned char* header,
                             unsigned short value);
void XDNS_SET_HEADER_ARCOUNT(unsigned char* header,
                             unsigned short value);

// Start from the pointer to QTYPE of the question section.
unsigned short XDNS_GET_QUESTION_TYPE(unsigned char* qtype);
unsigned short XDNS_GET_QUESTION_CLASS(unsigned char* qtype);
void XDNS_SET_QUESTION_TYPE(unsigned char* qtype,
                            unsigned short value);
void XDNS_SET_QUESTION_CLASS(unsigned char* qtype,
                             unsigned short value);

// Start from the pointer to TYPE of resource record section.
unsigned short XDNS_GET_RR_TYPE(unsigned char* type);
unsigned short XDNS_GET_RR_CLASS(unsigned char* type);
long XDNS_GET_RR_TTL(unsigned char* type);
unsigned short XDNS_GET_RR_RDLENGTH(unsigned char* type);
void XDNS_SET_RR_TYPE(unsigned char* type,
                      unsigned short value);
void XDNS_SET_RR_CLASS(unsigned char* type,
                       unsigned short value);
void XDNS_SET_RR_TTL(unsigned char* type,
                     long value);
void XDNS_SET_RR_RDLENGTH(unsigned char* type,
                          unsigned short value);

#endif  // XDNS_PROTOCOL_H

